package com.qingcloud.df.executor.utils;

import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.UnknownHostException;

import static cn.hutool.core.text.CharSequenceUtil.isNotBlank;

/**
 * 服务器相关工具类
 *
 * @author wangjinnan
 */
@Slf4j
public class ServerUtil {

    /**
     * 运行节点绑定的ip地址
     */
    private static String publishHost = "";

    public static void setPublishHost(String publishHost) {
        ServerUtil.publishHost = publishHost;
    }

    private ServerUtil() {
    }

    /**
     * 获取本机的IP地址
     */
    public static String getLocalIp() {
        return publishHost;
    }

    /**
     * 获取本机的host
     */
    public static String getHostname() {
        try {
            InetAddress addr = InetAddress.getLocalHost();
            return addr.getHostName();
        } catch (UnknownHostException e) {
            log.error(e.getMessage(), e);
        }
        return "";
    }

    /**
     * 字符串是否每个字符都是数字
     *
     * @param str 原始字符串
     * @return 是否数字 true是 false不是
     */
    private static boolean strIsNumber(String str) {
        for (int i = 0; i < str.length(); i++) {
            if (!Character.isDigit(str.charAt(i))) {
                return false;
            }
        }
        return true;
    }

    /**
     * 获取windows进程占用的端口
     *
     * @param processId 进程ID
     * @return 端口号，返回null说明没找到
     */
    public static Integer getWindowsProcessPort(Integer processId) {
        try {
            final Process process = Runtime.getRuntime().
                    exec("cmd.exe /c netstat -ano | findstr LISTENING | findstr " + processId);
            return readProcessPort(processId, process);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 获取类unix系统进程占用的端口
     *
     * @param processId 进程ID
     * @return 端口号，返回null说明没找到
     */
    public static Integer getUnixProcessPort(Integer processId) {
        try {
            final Process process = Runtime.getRuntime().exec("netstat -tnpl | grep " + processId);
            return readProcessPort(processId, process);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 从进程中读取端口
     *
     * @param processId 进程ID
     * @param process   进程
     * @return 端口号，返回null说明没找到端口号
     */
    private static Integer readProcessPort(Integer processId, Process process) {
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
            //读取标准输出
            String line;
            while ((line = reader.readLine()) != null) {
                if (line.contains(String.valueOf(processId))) {
                    log.debug("process [{}] port line is {}", processId, line);
                    final String[] ss = line.split(" ");
                    for (String str : ss) {
                        if (isNotBlank(str) && str.contains(":")) {
                            String[] split = str.split(":");
                            for (String port : split) {
                                if (isNotBlank(port) && strIsNumber(port)) {
                                    return Integer.valueOf(port);
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }
}
